Skip to content

Wrap recipe errors with RecipeError to attribute failures to a nested recipe#7568

Closed
steve-aom-elliott wants to merge 3 commits intomainfrom
feat/recipe-error-attribution
Closed

Wrap recipe errors with RecipeError to attribute failures to a nested recipe#7568
steve-aom-elliott wants to merge 3 commits intomainfrom
feat/recipe-error-attribution

Conversation

@steve-aom-elliott
Copy link
Copy Markdown
Contributor

Summary

The Consumer<Throwable> returned by ExecutionContext#getOnError() previously received the raw throwable from a failing recipe, leaving downstream tooling no way to tell which nested recipe — in a large declarative recipe with hundreds or thousands of children — actually produced the failure. The stack trace alone does not name the responsible recipe.

This PR introduces RecipeError, a RuntimeException that carries:

  • List<String> recipeStack — names from root to leaf at the time of failure
  • String sourcePath — the source file being processed (or "error during generation" for the scanning-generate path)

Wrapping happens at the single chokepoint RecipeRunCycle.handleError and at the per-cycle timeout site, immediately before invoking ctx.getOnError().accept(...). All six existing handleError callsites pass the recipe stack already in scope (either the lambda parameter from RecipeStack#reduce or the per-batch stack list from RPC batching), so no new bookkeeping is needed.

The SourcesFileErrors data table continues to receive the original sanitized stack trace via ExceptionUtils.sanitizeStackTrace, so attribution there is unchanged.

RewriteTest's default error consumer is updated to unwrap a RecipeError before its instanceof RecipeRunException check, so existing assertions keep working.

Test plan

  • rewrite-core full test suite passes
  • Three new tests in RecipeSchedulerTest cover: leaf attribution, full nested-stack attribution through a DeclarativeRecipe parent, and generate-time error wrapping
  • rewrite-test, rewrite-yaml, rewrite-properties, rewrite-json, rewrite-hcl all compile/test cleanly

Notes

  • Marking as draft pending review of the chosen attribution strategy and sizing of the RewriteTest ergonomics change.
  • A follow-up issue is planned for batched-RPC error attribution: RecipeRunCycle#flushBatch currently attributes a batch failure to the first recipe in the batch regardless of which visitor failed remotely. Properly fixing that requires a new failedIndex field on the RPC error response and updates across the Java/.NET/Node RPC implementations — out of scope here.

@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite May 4, 2026
@steve-aom-elliott steve-aom-elliott added enhancement New feature or request test provided Already replicated with a unit test, using JUnit pioneer's ExpectedToFail labels May 4, 2026
… recipe

The `Consumer<Throwable>` returned by `ExecutionContext#getOnError()` previously
received the raw throwable from a failing recipe, leaving downstream tooling no
way to tell which nested recipe (in a large declarative recipe with hundreds or
thousands of children) actually produced the failure.

Introduce `RecipeError` — a `RuntimeException` carrying the recipe path
(root → leaf) and source path — and wrap throwables at the single chokepoint
`RecipeRunCycle.handleError` and the run-timeout site before invoking the
`onError` consumer. The `SourcesFileErrors` data table continues to receive
the original sanitized stack trace, so attribution there is unchanged.

Update `RewriteTest`'s default consumer to unwrap the new `RecipeError`
before its `instanceof RecipeRunException` check.
@steve-aom-elliott steve-aom-elliott force-pushed the feat/recipe-error-attribution branch from 648d385 to 8b3259c Compare May 4, 2026 18:15
…unException

RewriteTest.defaultExecutionContext was passing the outer RecipeError to
fail(), which made the resulting AssertionError's cause RecipeError
instead of the underlying RecipeRunException. This regressed
RepeatTest.repeatValidatesCursorIsPassed, which asserts that the cause
is a RecipeRunException.
@steve-aom-elliott steve-aom-elliott marked this pull request as ready for review May 4, 2026 19:49
@steve-aom-elliott steve-aom-elliott moved this from In Progress to Ready to Review in OpenRewrite May 4, 2026
@steve-aom-elliott steve-aom-elliott marked this pull request as draft May 4, 2026 20:45
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request test provided Already replicated with a unit test, using JUnit pioneer's ExpectedToFail

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant